package com.cy.store.controller;

import com.cy.store.controller.ex.*;
import com.cy.store.entity.User;
import com.cy.store.service.IUserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import com.cy.store.util.JsonResults;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 用户控制类:控制类用于处理异常（已交给父类处理），设计请求和处理请求，和前端数据进行交互
 */
@RestController //表示该控制类都以Json格式进行响应
//@Controller
@RequestMapping("user")
public class UserController extends BaseController {
    @Autowired
    private IUserService userService;

    @RequestMapping("reg")
    //@ResponseBody //表示该方法以Json格式进行响应
    public JsonResults<Void> reg(User user){
//        JsonResults<Void> jsonResults = new JsonResults<Void>();
//        try {
//            userService.reg(user);
//            jsonResults.setState(200);
//            jsonResults.setMessage("注册成功！");
//        } catch (UsernameDuplicatedException e) {
//            jsonResults.setState(500);
//            jsonResults.setMessage("用户名被占用！");
//        }  catch (InsertException e){
//            jsonResults.setState(600);
//            jsonResults.setMessage("用户注册过程出现异常!");
//        }
//        return jsonResults;
        //将异常处理交给控制类的基类，简洁代码，解耦合
        userService.reg(user);
        return new JsonResults<>(OK);
    }

    @RequestMapping("login")
    //当用户进入登录页面时，输入完表单上的值后，前端发送Ajax请求并将表单上的元素遍历获取放入data中跟随Ajax发出，在此后端使用相同参数key进行获取，前后台key不一致时
    //后台参数列表上可以使用@RequestParam注解进行注入
    public JsonResults<User> login(String username, String password, HttpSession httpSession){
        User data = userService.login(username,password);
        //当用户登录成功后将uid以及username放进全局session中
        httpSession.setAttribute("uid",data.getUid());
        httpSession.setAttribute("username",data.getUsername());
        return new JsonResults<>(OK,data);
    }


    @RequestMapping("changePassword")
    public JsonResults<Void> changePassword(String oldPassword,
                                            String newPassword,
                                            HttpSession httpSession){
        //从session中获取登录用户的id和名字
        Integer uid = getuidFromSession(httpSession);
        String username = getUsernameFromSession(httpSession);
        userService.changePassword(uid,username,oldPassword,newPassword);
        return new JsonResults<>(OK);
    }

    /**
     *
     * @param httpSession
     * @return 返回值为user对象即从数据库中查出来的数据封装为user对象返回给前端用于显示
     */
    @RequestMapping("get_by_uid")
    public JsonResults<User> findByUid(HttpSession httpSession){
        User data = userService.findByUid(getuidFromSession(httpSession));
        return new JsonResults<>(OK,data);
    }

    /**
     *
     * @param user 该user对象为从前端接收到的user对象，即需要修改的数据
     * @param httpSession 全局session中获取用户名和用户id
     * @return
     */
    @RequestMapping("change_info")
    public JsonResults<Void> updateInfo(User user,
                                        HttpSession httpSession){
        Integer uid = getuidFromSession(httpSession);
        String username = getUsernameFromSession(httpSession);
        user.setUsername(username);
        user.setUid(uid);
        userService.updateInfo(uid,username,user);
        return new JsonResults<>(OK);
    }

    public static final int FILE_MAX_SZIE = 10*1024*1024;//单张照片最大不超过10MB

    /**
     * 储存照片类型的数组
     */
    public static final List<String> ARRAY_TYPE = new ArrayList<>();
    static{
        ARRAY_TYPE.add("image/jpeg");
        ARRAY_TYPE.add("image/png");
        ARRAY_TYPE.add("image/bmp");
        ARRAY_TYPE.add("image/gif");

    }

    /**
     * MultipartFile是SpringMVC提供的接口，可用来接收任何类型的数据，SpringBoot也整合了该接口。
     * @RequestParam类似于数据库接口文件中@Param，当表单中的名称和方法参数列表名称不一致时，使用该注解进行注入，即注解后的参数为前端参数名
     * 不加@RequestParam前端的参数名需要和后端控制器的变量名保持一致才能生效
     * 不加@RequestParam参数为非必传，加@RequestParam写法参数为必传。但@RequestParam可以通过@RequestParam(required = false)设置为非必传。
     * 访问时：不加@RequestParam注解：url可带参数也可不带参数，输入 localhost:8080/list1 以及 localhost:8080/list1?userId=xxx 方法都能执行
     * 加@RequestParam注解：url必须带有参数。也就是说你直接输入localhost:8080/list2 会报错，不会执行方法。只能输入localhost:8080/list2?userId=xxx 才能执行相应的方法
     *
     * @param httpSession
     * @param file
     * @return
     */
    @RequestMapping("change_avatar")
    public JsonResults<String> updateAvatar( HttpSession httpSession,
                                             @RequestParam("file") MultipartFile file){
        //判断文件是否为空
        if(file.isEmpty()){
            throw new FileEmptyException("文件为空！");
        }
        if(file.getSize() > FILE_MAX_SZIE){
            throw new FileSizeException("文件大小超出限制！");
        }
        String fileType = file.getContentType();
        if(!ARRAY_TYPE.contains(fileType)){
            throw new FileTypeException("文件类型不正确！");
        }
        //获取存放文件的目录
        String parent = httpSession.getServletContext().getRealPath("upload");
        System.out.println("==========文件目录结构=========="+parent);
        File dir = new File(parent);
        if(!dir.exists()){
            dir.mkdirs();
        }
        //获取当前上传文件名字，并使用UUID重新生成一个字符串当做该文件的新名字
        String originialName = file.getOriginalFilename();
        //截取名字的格式后缀
        int index = originialName.lastIndexOf(".");
        String suffix = originialName.substring(index);//截取结果为: .png
        String fileName = UUID.randomUUID().toString().toUpperCase()+suffix;
        //将空文件放入之前新建的目录下
        File dest = new File(dir,fileName);
        //将上传的头像文件写入新建的空文件中,transferTo是有SpringBoot集成的读写操作，相当于IO读写
        try {
            file.transferTo(dest);
        }catch (FileStateException e) {
            throw new FileStateException("文件状态异常！");
        }catch (IOException e) {
            throw new FileUploadException("文件读写出现IO异常！");
        }
        //获取存在session中的uid和用户名
        Integer uid = getuidFromSession(httpSession);
        String username = getUsernameFromSession(httpSession);
        String avatar = "/upload/"+fileName;
        userService.updateAvatar(uid,avatar,username);
        //将头像路径返回给前端用于头像展示
        return new JsonResults<>(OK,avatar);
    }
}
